package com.example.handler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;

import com.example.enums.BallEnum;
import com.example.enums.BaseEnum;

/**
 * Mybatis类型转换器：两种实现方式，一种是实现Typehandler接口，一种是继承BaseTypeHandler
 * @ClassName: EnumTypeHandler
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author liuwj3
 * @date 2019年2月15日 下午3:29:30
 *
 */
@MappedTypes(value = {BallEnum.class})
public class EnumTypeHandler<E extends BaseEnum<Enum<?>, Object>> extends BaseTypeHandler<E> {
	
	private Class<E> type;
	
	private E[] enums;
	
	public EnumTypeHandler(Class<E> type) {
		if (type == null) {
			throw new IllegalArgumentException("type argument cannot be null");
		}
		this.type = type;
		// 直接在构造函数中设置好枚举值，为其它方法调用提速
		this.enums = type.getEnumConstants();
		if (this.enums == null) {
			throw new IllegalArgumentException(type.getSimpleName() + "不能体现为一个枚举的类类型");
		}
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType)
			throws SQLException {
		// BaseTypeHandler已经帮我们做了parameter的null判断
		if (jdbcType == null) {
			ps.setObject(i, parameter.getValue().toString());
		} else {
			ps.setObject(i, parameter.getValue().toString(), jdbcType.TYPE_CODE);
		}
		
		
	}

	@Override
	public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
		Object value = rs.getString(columnName);
		if (value == null && rs.wasNull()) {
			return null;
		}
		return locateEnum(value); 
	}

	@Override
	public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		Object value = rs.getString(columnIndex);
		if (value == null && rs.wasNull()) {
			return null;
		}
		return locateEnum(value);
	}

	@Override
	public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		Object value = cs.getString(columnIndex);
		if (value == null && cs.wasNull()) {
			return null;
		}
		return locateEnum(value);
	}
	
	/**
	 * 通过value定位对应枚举
	 * @param value
	 * @return
	 */
	private E locateEnum(Object value) {
		for (E e : this.enums) {
			if (e.getValue() == value) {
				// 基本类型
				return e;
			} else if (e.getValue() instanceof Number) {
				if (value instanceof Number && ((Number) value).doubleValue() == ((Number) e.getValue()).doubleValue()) {
					return e;
				}
			} else if (Objects.equals(String.valueOf(value), String.valueOf(e.getValue()))) {
				return e;
			}
		}
		throw new IllegalArgumentException("未知的枚举类型：" + value + "，请核对" + this.type.getSimpleName());
	}

}
